package hypergraph;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class HyperEdge implements Comparable<HyperEdge> {
	private boolean					minPathMark;
	private int						weight;
	private String					name;
	private List<Node>				tails;
	private List<Node>				heads;
	
	private Set<HyperEdge>			minPath;
	private Set<HyperEdge>[]		paths;
	private int 					color;
	private boolean					touched;
	

	public HyperEdge(String name, int weight) {
		this.name = name;
		this.weight = weight;
		this.tails = null;
		this.heads = null;
		
		this.minPath = new HashSet<HyperEdge> ();
		this.paths =  null;
		this.touched = false;
	}
	
	@SuppressWarnings("unchecked")
	public HyperEdge(String name, int weight, List<Node> tails, List<Node> heads) {
		if (name == null || tails == null || heads == null) {
			throw new NullPointerException("null arguments");
		}
		
		if (weight <= 0) {
			throw new IllegalArgumentException("weight should be greater than zero");
		}
		
		if (tails.isEmpty() || heads.isEmpty()) {
			throw new IllegalArgumentException("Either hyperedge has no tail nodes or head nodes");
		}
		
		this.name = name;
		this.weight = weight;
		this.tails = tails;
		this.heads = heads;
		this.minPath = new HashSet<HyperEdge> ();
		this.paths =  new HashSet[tails.size()];
	}

	public int getColor() {
		return color;
	}

	public void paint(int color) {
		this.color = color;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (!(obj instanceof HyperEdge))
			return false;
		HyperEdge other = (HyperEdge) obj;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}

	public boolean isOpen(){
		for (int i = 0 ; i < paths.length ; i++) {
			if (paths[i] == null)
				return false;
		}
		return true;
	}
	
	/** Crea el camino minimo a partir de las hiperaristas que forman
	 * los caminos hacia esta hiperarista
	 */
	public Set<HyperEdge> evaluatePath(){
		
		for (int i = 0 ; i < this.paths.length ; i++) {
			this.minPath.addAll(paths[i]);
		}
		
		this.minPath.add(this);
		
		return this.minPath;
	}
	
	/** Evalua el peso del camino minimo hacia la hiperarista */
	public int evaluateWeight(){

		int acum=0;
		for( HyperEdge h: this.minPath ){
			acum += h.weight;
		}
		return acum;
	}
	
	public Set<HyperEdge> getMinPath() {
		return minPath;
	}
	
	public void setMinPath(Set<HyperEdge> minPath) {
		this.minPath = minPath;
	}

	@Override
	public int compareTo(HyperEdge o) {
		return this.evaluateWeight() - o.evaluateWeight();
	}

	public List<Node> getTails() {
		return tails;
	}

	@SuppressWarnings("unchecked")
	public void setTails(List<Node> tails) {
		this.tails = tails;
		this.paths = new HashSet[tails.size()];
	}

	public List<Node> getHeads() {
		return heads;
	}

	public void setHeads(List<Node> heads) {
		this.heads = heads;
	}

	public Set<HyperEdge>[] getPaths() {
		return paths;
	}
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	public boolean isMinPathMark() {
		return minPathMark;
	}

	public void setMinPathMark(boolean minPathMark) {
		this.minPathMark = minPathMark;
	}

	public int getWeight() {
		return weight;
	}

	public void setWeight(int weight) {
		this.weight = weight;
	}

	public boolean isTouched() {
		return touched;
	}

	public void setTouched(boolean touched) {
		this.touched = touched;
	}

	@Override
	public String toString() {
		return this.name;
	}
	
	public String toDotString() {
		if (this.minPathMark == true) {
			return this.name + " [shape=box, height=0.18, fontsize=12, label=\"" + this.name + "\", style=bold, color=red];";
		} else {
			return this.name + " [shape=box, height=0.18, fontsize=12, label=\"" + this.name + "\", style=dashed, color=black];";
		}
	}
	
	public void revertAndClear(){
		List<Node> aux = heads;
		heads = tails;
		tails = aux;
		minPathMark = false;
		minPath=null;
	}
		
	public static int getSetWeight(Set<HyperEdge> hset) {
		int weight = 0;
		
		if (hset == null) {
			throw new NullPointerException("null HyperEdge set");
		}
		
		if (hset.isEmpty()) {
			return 0;
		}
		
		for (HyperEdge ha : hset) {
			weight += ha.getWeight();
		}
		
		return weight;
	}
	
}
